﻿/*
 * deviceagent.hpp
 *
 *  Created on: 2017年3月27日
 *      Author: work
 */

#ifndef _DM_SCADA_DEVICEAGENT_HPP_
#define _DM_SCADA_DEVICEAGENT_HPP_

#include <dm/export.hpp>

#ifndef DM_API_SCADA
#define DM_API_SCADA DM_API_IMPORT
#endif

#include <dm/scada/devicemgr.hpp>
#include <dm/scada/deviceinfo.hpp>
#include <dm/scada/datasource.hpp>
#include <dm/timestamp.hpp>

#include <dm/scada/statusmgr.hpp>
#include <dm/scada/discretemgr.hpp>
#include <dm/scada/measuremgr.hpp>
#include <dm/scada/cumulantmgr.hpp>
#include <dm/scada/actionmgr.hpp>

#include <dm/scada/eventmgr.hpp>
#include <dm/scada/timedmeasuremgr.hpp>
#include <dm/scada/timedcumulantmgr.hpp>
#include <dm/scada/devicestate.hpp>

#include <dm/os/options.hpp>

namespace dm{
namespace scada{

/**
 * 设备代理器类
 * 封装了本地物理设备的数据接口。是重要的类。
 */
class DM_API_SCADA CDeviceAgent{
	CDeviceAgent( const CDeviceAgent& );
	CDeviceAgent& operator=( const CDeviceAgent& );

public:
	typedef dm::CTimeStamp ts_t;	//!< 时标类型

	typedef CStatusMgr::rt_t rt_s_t;
	typedef CDiscreteMgr::rt_t rt_d_t;
	typedef CMeasureMgr::rt_t rt_m_t;
	typedef CCumulantMgr::rt_t rt_c_t;

	typedef CStatus::value_t s_t;
	typedef CDiscrete::value_t d_t;
	typedef CMeasure::value_t m_t;
	typedef CCumulant::value_t c_t;

	/**
	 * 设备信号个数
	 */
	struct SSignalsSize{
		SSignalsSize():status(0),discrete(0),measure(0),cumulant(0),
				remoteCtl(0),parameter(0),action(0){
		}

		int status;			//!< 状态量个数
		int discrete;		//!< 离散量个数
		int measure;		//!< 测量量个数
		int cumulant;		//!< 累计量个数
		int remoteCtl;	//!< 远控量个数
		int parameter;	//!< 参数个数
		int action;			//!< 动作个数
	};

	static CDeviceAgent* findByName( const char* name );
	static CDeviceAgent* findByName( const char* name,const SSignalsSize& s );

	CDeviceAgent();
	CDeviceAgent( const id_t& id );
	CDeviceAgent( const char* name );

	/**
	 * 初始化设备
	 * @param idx 索引号
	 * @return
	 */
	bool setByIndex( const index_t& idx );
	bool setById( const id_t& id );
	bool setByName( const char* name );

	/**
	 * 初始化设备
	 * 本函数会检测给定的设备信号数量。如果不一致会报警或者返回失败
	 * @param idx 索引号
	 * @param size 信号个数
	 * @param error 信号不一致时，是否返回失败
	 * @return
	 */
	bool setByIndex( const index_t& idx,const SSignalsSize& size,bool error=true  );
	bool setById( const id_t& id,const SSignalsSize& size,bool error=true );
	bool setByName( const char* name,const SSignalsSize& size,bool error=true );

	/**
	 * 获取本设备的索引。
	 * 该索引可以用在CDeviceMgr中。
	 * @return
	 */
	inline const index_t& getIndex()const{
		return m_idx;
	}

	/**
	 * 获取设备信息
	 * @return
	 */
	inline const SDeviceInfo* info()const{
		return m_mgr.info(m_idx);
	}

	/**
	 * 获取设备状态
	 * @return
	 */
	inline const CDeviceState* state()const{
		return m_state;
	}

	/**
	 * 获取设备状态
	 * @return
	 */
	inline CDeviceState* state(){
		return m_state;
	}

	// 注意，本类处理的index都是相对于本设备的所以，不是全局的

	bool updateStatus( const index_t& status,const CStatus& value,const EDataSource& ds=ByCollector,const ts_t& ts=ts_t::cur() );
	bool updateDiscrete( const index_t& discrete,const CDiscrete& value,const EDataSource& ds=ByCollector,const ts_t& ts=ts_t::cur() );
	bool updateMeasure( const index_t& measure,const CMeasure::raw_t& raw,const EDataSource& ds=ByCollector,const ts_t& ts=ts_t::cur() );
	bool updateCumulant( const index_t& cumulant,const CCumulant::raw_t& raw,const EDataSource& ds=ByCollector,const ts_t& ts=ts_t::cur() );

	bool setStatus( const index_t& status,const CStatus& value,const EDataSource& ds=ByCollector,const ts_t& ts=ts_t::cur() );
	bool setDiscrete( const index_t& discrete,const CDiscrete& value,const EDataSource& ds=ByCollector,const ts_t& ts=ts_t::cur() );
	bool setMeasure( const index_t& measure,const CMeasure::raw_t& raw,const EDataSource& ds=ByCollector,const ts_t& ts=ts_t::cur() );
	bool setCumulant( const index_t& cumulant,const CCumulant::raw_t& raw,const EDataSource& ds=ByCollector,const ts_t& ts=ts_t::cur() );

	bool genStatus( const index_t& status,const CStatus& value,const ts_t& ts=ts_t::cur());
	bool genDiscrete( const index_t& discrete,const CDiscrete& value,const ts_t& ts=ts_t::cur() );
	bool genMeasure( const index_t& measure,const CMeasure::raw_t& raw,const ts_t& ts=ts_t::cur() );
	bool genCumulant( const index_t& cumulant,const CCumulant::raw_t& raw,const ts_t& ts=ts_t::cur() );
	bool genAction( const index_t& action,const CAction::value_t& value,const ts_t& ts=ts_t::cur() );

	/**
	 * 是否时本设备的远控
	 * @param rc
	 * @return
	 */
	inline bool isMyRemoteCtl( const index_t& rc )const{
		return -1!=getLocalRemoteControlIndex(rc);
	}

	/**
	 * 是否是本设备的参数
	 * @param pm
	 * @return
	 */
	inline bool isMyParameter( const index_t& pm )const{
		return -1!=getLocalParamterIndex(pm);
	}

	index_t getLocalStatusIndex( const index_t& idx )const;
	index_t getLocalDiscreteIndex( const index_t& idx )const;
	index_t getLocalMeasureIndex( const index_t& idx )const;
	index_t getLocalCumulantIndex( const index_t& idx )const;
	index_t getLocalRemoteControlIndex( const index_t& idx )const;
	index_t getLocalParamterIndex( const index_t& idx )const;
	index_t getLocalActionIndex( const index_t& idx )const;

	index_t getStatusIndex( const index_t& idx )const;
	index_t getDiscreteIndex( const index_t& idx )const;
	index_t getMeasureIndex( const index_t& idx )const;
	index_t getCumulantIndex( const index_t& idx )const;
	index_t getRemoteControlIndex( const index_t& idx )const;
	index_t getParameterIndex( const index_t& idx )const;
	index_t getActionIndex( const index_t& idx )const;

	const rt_s_t* rtStatuses()const;
	const rt_d_t* rtDiscretes()const;
	const rt_m_t* rtMeasures()const;
	const rt_c_t* rtCumulants()const;

	rt_s_t* rtStatuses();
	rt_d_t* rtDiscretes();
	rt_m_t* rtMeasures();
	rt_c_t* rtCumulants();

	const rt_s_t* rtStatus( index_t idx )const;
	const rt_d_t* rtDiscrete( index_t idx )const;
	const rt_m_t* rtMeasure( index_t idx )const;
	const rt_c_t* rtCumulant( index_t idx )const;

	s_t rtStatusV( index_t idx )const;
	d_t rtDiscreteV( index_t idx )const;
	m_t rtMeasureV( index_t idx )const;
	c_t rtCumulantV( index_t idx )const;

	bool loadStatusByOption_int( const char* gorup,const char* option,index_t idx,int v=0 );
	bool loadStatusByOption_int( dm::env::COptions& op,const char* gorup,const char* option,index_t idx,int v=0 );

	bool loadDiscreteByOption_int( const char* group,const char* option,index_t idx,int v=0 );
	bool loadDiscreteByOption_int( dm::env::COptions& op,const char* group,const char* option,index_t idx,int v=0 );

	bool loadMeasureByOption_float( const char* group,const char* option,index_t idx,float v=0 );
	bool loadMeasureByOption_float( dm::env::COptions& op,const char* group,const char* option,index_t idx,float v=0 );

	bool loadMeasureByOption_int( const char* group,const char* option,index_t idx,int v=0 );
	bool loadMeasureByOption_int( dm::env::COptions& op,const char* group,const char* option,index_t idx,int v=0 );

	bool loadCumulantByOption_int( const char* group,const char* option,index_t idx,int v=0 );
	bool loadCumulantByOption_int( dm::env::COptions& op,const char* group,const char* option,index_t idx,int v=0 );

	bool updateStatusWithOption_int( const char* group,const char* option,index_t idx,int v );
	bool updateStatusWithOption_int( dm::env::COptions& op,const char* group,const char* option,index_t idx,int v );

	bool updateDiscreteWithOption_int( const char* group,const char* option,index_t idx,int v );
	bool updateDiscreteWithOption_int( dm::env::COptions& op,const char* group,const char* option,index_t idx,int v );

	bool updateMeasureWithOption_float( const char* group,const char* option,index_t idx,float v );
	bool updateMeasureWithOption_float( dm::env::COptions& op,const char* group,const char* option,index_t idx,float v );

	bool updateMeasureWithOption_int( const char* group,const char* option,index_t idx,int v );
	bool updateMeasureWithOption_int( dm::env::COptions& op,const char* group,const char* option,index_t idx,int v );

	bool updateCumulantWithOption_int( const char* group,const char* option,index_t idx,int v );
	bool updateCumulantWithOption_int( dm::env::COptions& op,const char* group,const char* option,index_t idx,int v );

	inline bool loadStatusByOption_int( const char* option,index_t idx,int v=0 ){
		return loadStatusByOption_int(info()->name.c_str(),option,idx,v);
	}

	inline bool loadStatusByOption_int( dm::env::COptions& op,const char* option,index_t idx,int v=0 ){
		return loadStatusByOption_int(op,info()->name.c_str(),option,idx,v);
	}

	inline bool loadDiscreteByOption_int( const char* option,index_t idx,int v=0){
		return loadDiscreteByOption_int(info()->name.c_str(),option,idx,v);
	}

	inline bool loadDiscreteByOption_int( dm::env::COptions& op,const char* option,index_t idx,int v=0 ){
		return loadDiscreteByOption_int(op,info()->name.c_str(),option,idx,v);
	}

	inline bool loadMeasureByOption_float( const char* option,index_t idx,float v=0 ){
		return loadMeasureByOption_float(info()->name.c_str(),option,idx,v);
	}

	inline bool loadMeasureByOption_float( dm::env::COptions& op,const char* option,index_t idx,float v=0 ){
		return loadMeasureByOption_float(op,info()->name.c_str(),option,idx,v);
	}

	inline bool loadMeasureByOption_int( const char* option,index_t idx,int v=0 ){
		return loadMeasureByOption_int(info()->name.c_str(),option,idx,v);
	}

	inline bool loadMeasureByOption_int( dm::env::COptions& op,const char* option,index_t idx,int v=0 ){
		return loadMeasureByOption_int(op,info()->name.c_str(),option,idx,v);
	}

	inline bool loadCumulantByOption_int( const char* option,index_t idx,int v=0 ){
		return loadCumulantByOption_int(info()->name.c_str(),option,idx,v);
	}

	inline bool loadCumulantByOption_int( dm::env::COptions& op,const char* option,index_t idx,int v=0 ){
		return loadCumulantByOption_int(op,info()->name.c_str(),option,idx,v);
	}

	inline bool updateStatusWithOption_int( const char* option,index_t idx,int v ){
		return updateStatusWithOption_int(info()->name.c_str(),option,idx,v);
	}

	inline bool updateStatusWithOption_int( dm::env::COptions& op,const char* option,index_t idx,int v ){
		return updateStatusWithOption_int(op,info()->name.c_str(),option,idx,v);
	}

	inline bool updateDiscreteWithOption_int( const char* option,index_t idx,int v ){
		return updateDiscreteWithOption_int(info()->name.c_str(),option,idx,v);
	}

	inline bool updateDiscreteWithOption_int( dm::env::COptions& op,const char* option,index_t idx,int v ){
		return updateDiscreteWithOption_int(op,info()->name.c_str(),option,idx,v);
	}

	inline bool updateMeasureWithOption_float( const char* option,index_t idx,float v ){
		return updateMeasureWithOption_float(info()->name.c_str(),option,idx,v);
	}

	inline bool updateMeasureWithOption_float( dm::env::COptions& op,const char* option,index_t idx,float v ){
		return updateMeasureWithOption_float(op,info()->name.c_str(),option,idx,v);
	}

	inline bool updateMeasureWithOption_int( const char* option,index_t idx,int v ){
		return updateMeasureWithOption_int(info()->name.c_str(),option,idx,v);
	}

	inline bool updateMeasureWithOption_int( dm::env::COptions& op,const char* option,index_t idx,int v ){
		return updateMeasureWithOption_int(op,info()->name.c_str(),option,idx,v);
	}

	inline bool updateCumulantWithOption_int( const char* option,index_t idx,int v ){
		return updateCumulantWithOption_int(info()->name.c_str(),option,idx,v );
	}

	inline bool updateCumulantWithOption_int( dm::env::COptions& op,const char* option,index_t idx,int v ){
		return updateCumulantWithOption_int(op,info()->name.c_str(),option,idx,v);
	}

private:
	CDeviceMgr& m_mgr;
	index_t m_idx;	//!< 本设备索引号
	CDeviceState* m_state;	//!< 本设备状态
};

}
}

#endif /* INCLUDE_DM_SCADA_DEVICEAGENT_HPP_ */
